package com.example.demo.unitls;

import com.alibaba.fastjson2.JSON;
import com.example.demo.domain.security.GlobalAuthenticationUser;
import com.example.demo.domain.security.Token;
import com.example.demo.security.userdetails.ManagerUserDetails;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.impl.DefaultClaims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * @author 叮当猫的百宝箱
 * @since 1.0
 */
@Slf4j
@Component
public class TokenUtils {

    @Value("${erp.token.secret:secret}")
    private String secret;

    @Value("${erp.token.expiration:604800}")
    private Long expiration;

    @Value("${erp.token.issuer:TL}")
    private String issuer;

    @Value("${erp.token.type:Bearer}")
    private String type;


    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    private Token generateToken(Claims claims) {
        Date date = generateExpirationDate();
        // 生成一个token字符串
        String tokenString = Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();

        Token token = new Token();
        token.setExpiration(date.getTime());
        token.setType(type);
        token.setToken(tokenString);
        return token;
    }

    private Claims parseToken(String token) {
        return Jwts.parser()
                .setSigningKey(secret)
                .parseClaimsJws(token)
                .getBody();
    }

    public Token generateToken(UserDetails userDetails) {
        GlobalAuthenticationUser globalAuthenticationUser = new GlobalAuthenticationUser();

        if (userDetails instanceof ManagerUserDetails) {
            ManagerUserDetails managerUserDetails = (ManagerUserDetails) userDetails;
            globalAuthenticationUser.setId(managerUserDetails.getId());
            globalAuthenticationUser.setUsername(managerUserDetails.getUsername());
            globalAuthenticationUser.setType("MANAGER");
        }

        Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
        List<String> permissions = new ArrayList<>();
        for (GrantedAuthority authority : authorities) {
            permissions.add(authority.getAuthority());
        }

        globalAuthenticationUser.setAuthorities(permissions);

        Claims claims = new DefaultClaims();
        claims.setIssuer(issuer)
                .setAudience(globalAuthenticationUser.getType())
                .setSubject(JSON.toJSONString(globalAuthenticationUser))
                .setExpiration(generateExpirationDate())
                .setIssuedAt(new Date())
                .setNotBefore(new Date());

        return generateToken(claims);
    }

    public UserDetails getUserDetailsByToken(String token) {
        UserDetails userDetails = null;
        if (token != null && token.startsWith(type)) {
            token = token.substring(type.length());
            Claims claims = parseToken(token);

            String subject = claims.getSubject();
            GlobalAuthenticationUser globalAuthenticationUser = JSON.parseObject(subject, GlobalAuthenticationUser.class);

            // 是一个后台管理员认证对象
            if ("MANAGER".equals(globalAuthenticationUser.getType())) {
                ManagerUserDetails managerUserDetails = new ManagerUserDetails();
                managerUserDetails.setId(globalAuthenticationUser.getId());
                managerUserDetails.setUsername(globalAuthenticationUser.getUsername());

                List<String> permissions = globalAuthenticationUser.getAuthorities();
                List<GrantedAuthority> authorities = new ArrayList<>();
                for (String permission : permissions) {
                    authorities.add((GrantedAuthority) () -> permission);
                }
                managerUserDetails.setAuthorities(authorities);

                userDetails = managerUserDetails;
            }

        }

        return userDetails;

    }

    public UserDetails getUserDetailsByContextHolder() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        UserDetails userDetails = null;
        if (authentication != null && authentication.getPrincipal() instanceof UserDetails) {
            userDetails = (UserDetails) authentication.getPrincipal();
        }
        return userDetails;
    }

}
